package com.stp.config.filter;

import cn.hutool.core.util.StrUtil;
import com.stp.config.sign.Signature;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

/**
 * 签名拦截器
 */
@Component
@Slf4j
public class SignInterceptor implements HandlerInterceptor {

    @Value("${secret-key}")
    private String appSecret;

    @Resource
    private RedisTemplate<String,String> redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //分配的应用id
        String appId = request.getHeader("appId");
        //时间戳
        String timestampStr = request.getHeader("timestamp");
        //签名
        String signature = request.getHeader("signature");
        if(StrUtil.isBlank(appId) || StrUtil.isBlank(timestampStr) || StrUtil.isBlank(signature)){
            response.setStatus(500);
            response.getWriter().println("参数错误!");
            return false;
        }

        //实际场景中 一个用户会有多个appId(应用),一个appId对应一个appSecret
        //需要根据token或者其他条件去查询数据库 拿到appId对应的和appSecret ,然后进行解析签名
        String origin = appId + "\n" + appSecret + "\n" + timestampStr;
        if(!Signature.verify(appSecret, origin, signature)){
            response.setStatus(500);
            response.getWriter().println("签名错误!");
            return false;
        }

        //如果需要每次签名只能使用一次,使用Redis进行存储。客户端就不能生成一次签名，从而请求两次以上
        /*String redisKey = "sign:nonce:"+origin;
        if(!redisTemplate.opsForValue().setIfAbsent(redisKey,"1",10, TimeUnit.MINUTES)){
            response.setStatus(500);
            response.getWriter().println("签名过期!");
            return false;
        }*/

        //业务的时间戳
        long timestamp = Long.parseLong(timestampStr);
        //当前时间戳
        long currentTimestamp = System.currentTimeMillis() / 1000;
        //10分钟内有效
        long timeDifference = 10 * 60;
        if(Math.abs(timestamp - currentTimestamp) > timeDifference){
            response.setStatus(500);
            response.getWriter().println("签名过期!");
            return false;
        }

        //放行
        return true;
    }
}
